package com.yx.cloud.map3d;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;

import com.aaa.lib.map.area.LineArea;
import com.aaa.lib.map.area.RectangleArea;
import com.aaa.lib.map3d.Map3DSurfaceView;
import com.aaa.lib.map3d.model.LineModel;
import com.aaa.lib.map3d.model.Model;
import com.aaa.lib.map3d.obj.MultiObj3D;
import com.aaa.lib.map3d.obj.Path3D;
import com.aaa.lib.map3d.obj.Plane3D;
import com.iot.product.sweeper.bean.Furniture;
import com.yx.cloud.R;
import com.iot.product.sweeper.bean.AreaInfo;
import com.iot.product.sweeper.bean.Map;
import com.iot.product.sweeper.bean.MapInfo;
import com.iot.product.sweeper.bean.Path;
import com.iot.product.sweeper.bean.Power;
import com.iot.product.sweeper.bean.Room;
import com.iot.product.sweeper.bean.Sweeper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Room3DSurfaceView extends Map3DSurfaceView {
    public static final int TYPE_CLEAN_AREA = 0;
    public static final int TYPE_FORBIDDEN_AREA = 1;
    public static final int TYPE_FORBIDDEN_LINE = 3;
    public static final int TYPE_FORBIDDEN_MOP = 5;
    public static final int TYPE_LOCATION = 4;
    public static final int TYPE_ROOM = 2;
    public Bitmap floorBitmap;
    public Bitmap floorNormalBitmap;
    public Bitmap wallBitmap;
    public Bitmap wallNormalBitmap;
    public Bitmap cleanAreaBitmap;
    public Bitmap forbidAreaBitmap;
    private MapModel mapModel;
    private LineModel pathModel;
    private SweeperModel sweeperModel;
    private PowerModel powerModer;
    private int pathColor = Color.WHITE;
    private ModelLoader loader;
    private float mapOffsetX, mapOffsetY;
    private float unit;

    public Room3DSurfaceView(Context context) {
        super(context);
        initModel();
    }

    public Room3DSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initModel();
    }

    private void initModel() {
//        floorBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.texture_woodfloor);
        floorBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.texture_green_floor);
        floorNormalBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.texture_woodfloor_normal);
//        wallBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.texture_brickwall);
        wallBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.texture_white_wall);
        wallNormalBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.texture_brickwall_normal);
        cleanAreaBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.texture_clean_area);
        forbidAreaBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.texture_forbid_area);
        mapModel = new MapModel();
        addModel(mapModel);
        pathModel = new LineModel();
        addModel(pathModel);
        loader = ModelLoader.getInstance();
    }

    public void refreshMap(Map map) {
        refreshMap(map.getMap());
        refreshPath(map.getPath());
        refreshPower(map.getPower());
        refreshSweeper(map.getSweeper());
        refreshArea(map.getArea());
        refreshRoom(map.getRoom());
        refreshFurnitures(map.getFurniture());
    }

    /**
     * 刷新地图
     */
    public void refreshMap(MapInfo mapInfo) {
        int[] mapdata = new int[mapInfo.mapData.length];
        System.arraycopy(mapInfo.mapData, 0, mapdata, 0, mapInfo.mapData.length);

        refreshMap(mapInfo.width, mapInfo.height, mapInfo.resolution, mapInfo.mapData);
    }

    /**
     * 刷新地图
     */
    public void refreshMap(int width, int height, float unit, int[] mapData) {
        Log.i("setmodel ", "model " + " map w h :" + width + " " + height);
        this.unit = unit;

        //处理墙内的柱子, 如果 相邻的柱子少于10个, 就认为是墙内
//        MapDataConverter.filterWall(mapInfo.width, mapInfo.height, mapInfo.mapData, 10);

        //判断点是否在框框内
        MapDataConverter.filterBorder(width, height, mapData);

        //计算地图可裁剪区域 用于居中
        int[] clipArea = MapDataConverter.getClipArea(width, height, mapData);
        Log.i("setmodel ", "model " + " map clip :" + Arrays.toString(clipArea));
        mapOffsetX = (clipArea[2] + clipArea[0]) / 2.0f;
        mapOffsetY = (clipArea[3] + clipArea[1]) / 2.0f;

        float eyeDistance = (width > height ? width : height) * unit;
        if (eyeDistance == 0) {
            //防止设置视台体矩阵崩溃
            eyeDistance = 5;
        }

        moveTo(0, eyeDistance, 0); //根据地图大小设置眼睛位置
        setSight(1, eyeDistance + eyeDistance / 2);  //根据地图大小设置视台体大小
        setShadowSight(eyeDistance);

        MultiObj3D obj3D = MapDataConverter.mapDataToObj3D(this, width, height, mapData, unit);

        setModelTransform(mapModel, 0, -unit / 2, 0, 1, 0);
        updateModelData(mapModel, obj3D);

        requestRender();
    }

    /**
     * @param path 路径数据 格式: [x1,y1,x2,y2,x3,y3.......]
     */
    public void refreshPath(Path path) {
        Path3D path3DData = MapDataConverter.convertPathData(path.destPathPoints, pathColor, unit);
        setModelTransform(pathModel, 0, 0, 0, 1, 0);
        updateModelData(pathModel, path3DData);
        requestRender();
    }

    /**
     * 刷新区域
     * @param areaList 区域列表
     */
    public void refreshArea(List<AreaInfo> areaList) {
        removeArea();
        for (int i = 0; i < areaList.size(); i++) {
            AreaInfo areaBean = areaList.get(i);
            if (areaBean.getType() == TYPE_CLEAN_AREA) {
                RectangleArea area = new RectangleArea();
                area.setRect((float) (double) (areaBean.getBorder().get(0)),
                        (float) (double) areaBean.getBorder().get(1),
                        (float) (double) areaBean.getBorder().get(2),
                        (float) (double) areaBean.getBorder().get(3),
                        (float) (double) areaBean.getBorder().get(4),
                        (float) (double) areaBean.getBorder().get(5),
                        (float) (double) areaBean.getBorder().get(6),
                        (float) (double) areaBean.getBorder().get(7));
                Plane3D areaObject = MapDataConverter.areaToObj(unit, area);
                areaObject.bitmap = cleanAreaBitmap;
                AreaModel areaModel = new AreaModel(areaObject);
                areaModel.setRotate(0, area.rotate, 0);
                setModelTransform(areaModel, 0, 0, 0, 1, 0);
                addModel(areaModel);
            } else if (areaBean.getType() == TYPE_FORBIDDEN_AREA || areaBean.getType() == TYPE_FORBIDDEN_MOP) {
                RectangleArea area = new RectangleArea();
                area.setRect((float) (double) (areaBean.getBorder().get(0)),
                        (float) (double) areaBean.getBorder().get(1),
                        (float) (double) areaBean.getBorder().get(2),
                        (float) (double) areaBean.getBorder().get(3),
                        (float) (double) areaBean.getBorder().get(4),
                        (float) (double) areaBean.getBorder().get(5),
                        (float) (double) areaBean.getBorder().get(6),
                        (float) (double) areaBean.getBorder().get(7));
                Plane3D areaObject = MapDataConverter.areaToObj(unit, area);
                areaObject.bitmap = forbidAreaBitmap;
                AreaModel areaModel = new AreaModel(areaObject);
                areaModel.setRotate(0, area.rotate, 0);
                setModelTransform(areaModel, 0, 0, 0, 1, 0);
                addModel(areaModel);
            } else if (areaBean.getType() == TYPE_FORBIDDEN_LINE) {
                LineArea area = new LineArea();
                area.setLine((float) (double) (areaBean.getBorder().get(0)),
                        (float) (double) areaBean.getBorder().get(1),
                        (float) (double) areaBean.getBorder().get(2),
                        (float) (double) areaBean.getBorder().get(3));
                Plane3D plane3d = MapDataConverter.lineToObj(unit, area);
                plane3d.bitmap = forbidAreaBitmap;
                AreaModel areaModel = new AreaModel(plane3d);
                setModelTransform(areaModel, 0, 0, 0, 1, 0);
                addModel(areaModel);
            }
        }
        requestRender();
    }

    public void removeArea() {
        List<AreaModel> areaModelList = getAreaModel();
        modelManager.getAllModel().removeAll(areaModelList);
    }

    public List<AreaModel> getAreaModel() {
        List<AreaModel> areaModels = new ArrayList<>();
        for (int i = 0; i < modelManager.getAllModel().size(); i++) {
            Model model = modelManager.getAllModel().get(i);
            if (model instanceof AreaModel) {
                areaModels.add((AreaModel) model);
            }
        }
        return areaModels;
    }

    public void refreshRoom(List<Room> roomList) {
    }


    private void removeFurniture() {
        List<FurnitureModel> furnitureModelList = getFurnitureModel();
        modelManager.getAllModel().removeAll(furnitureModelList);
    }

    private List<FurnitureModel> getFurnitureModel() {
        List<FurnitureModel> furnitureModelList = new ArrayList<>();
        for (int i = 0; i < modelManager.getAllModel().size(); i++) {
            Model model = modelManager.getAllModel().get(i);
            if (model instanceof FurnitureModel) {
                furnitureModelList.add((FurnitureModel) model);
            }
        }
        return furnitureModelList;
    }

    /**
     * 刷新扫地机
     */
    public void refreshSweeper(Sweeper sweeper) {
        if (sweeper == null) {
            modelManager.removeModel(sweeperModel);
            requestRender();
            return;
        }

        if (sweeperModel == null) {
            //TODO 需要在子线程中操作
            Log.i("refreshPower ", "refreshSweeper " + " map offset x :" + sweeper.getX() + "  y " + sweeper.getY());
            MultiObj3D multiObj3D = loader.loadModel(getContext(), "assets/obj/扫地机器人.obj");
            sweeperModel = new SweeperModel(multiObj3D);
            setModelTransform(sweeperModel, (float) sweeper.getX(), multiObj3D.getModelHeigh() / 2, (float) sweeper.getY(), 1, sweeper.getRotation());
            addModel(sweeperModel);
        } else {
            setModelTransform(sweeperModel, (float) sweeper.getX(), sweeperModel.getData().getModelHeigh() / 2, (float) sweeper.getY(), 1, sweeper.getRotation());
        }
        requestRender();
    }

    /**
     * 刷新充电座
     * TODO 没有充电座和扫地机时显示在00位置 需改
     */
    public void refreshPower(Power power) {
        if (power == null || (power.x == 0 && power.y == 0)) {
            modelManager.removeModel(powerModer);
            requestRender();
            return;
        }


        if (powerModer == null) {
            //TODO 需要在子线程中操作
            Log.i("refreshPower ", "refreshPower " + " map offset x :" + power.getX() + "  y " + power.getY());
            MultiObj3D multiObj3D = loader.loadModel(getContext(), "assets/obj/充电座.obj");
            powerModer = new PowerModel(multiObj3D);
            setModelTransform(powerModer, (float) power.getX(), powerModer.getData().getModelHeigh() / 2 * 0.1f, (float) power.getY(), 0.1f, power.getRotation());
            addModel(powerModer);
        } else {
            setModelTransform(powerModer, (float) power.getX(), powerModer.getData().getModelHeigh() / 2 * 0.1f, (float) power.getY(), 0.1f, power.getRotation());
        }
        requestRender();
    }

    /**
     * 刷新家具列表
     * 先清空 再加载
     *
     * @param furnitures 家具列表
     */
    public void refreshFurnitures(List<Furniture> furnitures) {
        if (furnitures == null) {
            return;
        }

        List<Model> furnitureModels = new ArrayList<>();
        for (int i = 0; i < furnitures.size(); i++) {
            Furniture furniture = furnitures.get(i);
            FurnitureModel model = getModelById(furniture.getId());
            if (model != null) {
                setModelTransform(model, furniture.getX(), model.getData().getModelHeigh() / 2, furniture.getY(), furniture.getScale(), furniture.getRotation());
            } else {
                MultiObj3D multiObj3D = (MultiObj3D) loader.getModelDataByName(furniture.getName());
                if (multiObj3D == null) {
                    multiObj3D = loader.loadModel(getContext(), furniture.getName());
                }
                final FurnitureModel newModel = new FurnitureModel(multiObj3D);
                setModelTransform(newModel, furniture.getX(), multiObj3D.getModelHeigh() / 2, furniture.getY(), furniture.getScale(), furniture.getRotation());
                furnitureModels.add(newModel);
            }
        }
        removeFurniture();//移除的时候注意 移除回调里有没有把model数据清掉
        modelManager.addModels(furnitureModels);
        requestRender();
    }

    /**
     * 刷新任意家具, 如果当前没添加加创建
     *
     * @param furniture
     */
    public void refreshFurniture(Furniture furniture) {
        if (furniture == null) {
            return;
        }

        FurnitureModel furnitureModel = getModelById(furniture.getId());
        if (furnitureModel != null) {
            setModelTransform(furnitureModel, furniture.getX(), furnitureModel.getData().getModelHeigh() / 2, furniture.getY(), furniture.getScale(), furniture.getRotation());
        } else {
            MultiObj3D data = (MultiObj3D) loader.getModelDataByName(furniture.getName());
            if (data == null) {
                data = loader.loadModel(getContext(), furniture.getName());
            }

            final FurnitureModel newModel = new FurnitureModel(data);
            setModelTransform(newModel, furniture.getX(), data.getModelHeigh() / 2, furniture.getY(), furniture.getScale(), furniture.getRotation());
            addModel(newModel);

        }
        requestRender();
    }

    /**
     * 根据id查找家具模型
     *
     * @return FurnitureModel
     */
    private FurnitureModel getModelById(int id) {
        for (Model model : modelManager.getObjModel()) {
            if (model instanceof FurnitureModel && ((FurnitureModel) model).getId() == id) {
                return ((FurnitureModel) model);
            }
        }
        return null;
    }

    /**
     * @param x        y  平移 xy 对应3d内的xz  3维的y轴偏移需要平移半个模型高度
     * @param scale    如果模型大小单位为m 且与实际大小一致 则 scale==1
     * @param rotation 家具只按y轴旋转
     */
    private void setModelTransform(Model model, float x, float y, float z, float scale, float rotation) {
        model.setScale(scale);

        Log.i("setModelTransform ", "model " + " map offset :" + mapOffsetX + " " + y + " " + mapOffsetY);
        Log.i("setModelTransform ", "model " + " offset :" + x + " " + y + " " + z);
        model.setOffset((x - mapOffsetX) * unit, y, (z - mapOffsetY) * unit);
        Log.i("setModelTransform ", "model " + " offset :" + Arrays.toString(model.getOffset()));
        model.setRotate(0, rotation, 0);
    }

}
